package com.a0soft.gphone.aTruffleHog.di;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Alger Lin <addre75 (at) gmail.com>
 *
 */

import android.hardware.Sensor;
import android.hardware.SensorManager;
import com.a0soft.gphone.aTruffleHog.util.CONSTS;
import com.a0soft.gphone.aTruffleHog.util.MiscUtil;
import com.a0soft.gphone.aTruffleHog.util.Wrapper;
import com.a0soft.gphone.aTruffleHog.util.aDebug;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;


/**Agent to collects sensors' information.*/
public class SensorInfo extends BaseInfo {
    /**Tag for log.*/
    private static final String     LOG_TAG = SensorInfo.class.getSimpleName(); 
    /**Key set for accelerometer sensor.*/
    private static final KeySet     KEYSET_ACC = new KeySet(DeviceInfoKey.K.SS_ACC_NAME,        //Key for sensor name
                                                            DeviceInfoKey.K.SS_ACC_VENDOR,      //Key for sensor vendor
                                                            DeviceInfoKey.K.SS_ACC_VERSION,     //Key for sensor version
                                                            DeviceInfoKey.K.SS_ACC_POWER,       //Key for sensor power consumption
                                                            DeviceInfoKey.K.SS_ACC_RESOLUTION,  //Key for sensor resolution
                                                            DeviceInfoKey.K.SS_ACC_MAX,         //Key for sensor's maximum range
                                                            DeviceInfoKey.K.SS_ACC_MIN_DELAY);  //Key for sensor's minimum delay
    /**Key set for gravity sensor.*/
    private static final KeySet     KEYSET_GRAV = new KeySet(DeviceInfoKey.K.SS_GRAVITY_NAME,       //Key for sensor name
                                                             DeviceInfoKey.K.SS_GRAVITY_VENDOR,     //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_GRAVITY_VERSION,    //Key for sensor version
                                                             DeviceInfoKey.K.SS_GRAVITY_POWER,      //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_GRAVITY_RESOLUTION, //Key for sensor resolution
                                                             DeviceInfoKey.K.SS_GRAVITY_MAX,        //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_GRAVITY_MIN_DELAY); //Key for sensor's minimum delay
    /**Key set for gyroscope sensor.*/
    private static final KeySet     KEYSET_GYRO = new KeySet(DeviceInfoKey.K.SS_GYRO_NAME,      //Key for sensor name
                                                             DeviceInfoKey.K.SS_GYRO_VENDOR,    //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_GYRO_VERSION,   //Key for sensor version
                                                             DeviceInfoKey.K.SS_GYRO_POWER,     //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_GYRO_RESOLUTION,//Key for sensor resolution
                                                             DeviceInfoKey.K.SS_GYRO_MAX,       //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_GYRO_MIN_DELAY);//Key for sensor's minimum delay
    /**Key set for relative humidity sensor.*/
    private static final KeySet     KEYSET_HUMI = new KeySet(DeviceInfoKey.K.SS_HUMID_NAME,         //Key for sensor name
                                                             DeviceInfoKey.K.SS_HUMID_VENDOR,       //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_HUMID_VERSION,      //Key for sensor version
                                                             DeviceInfoKey.K.SS_HUMID_POWER,        //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_HUMID_RESOLUTION,   //Key for sensor resolution
                                                             DeviceInfoKey.K.SS_HUMID_MAX,          //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_HUMID_MIN_DELAY);   //Key for sensor's minimum delay
    /**Key set for light sensor.*/
    private static final KeySet     KEYSET_LIGH = new KeySet(DeviceInfoKey.K.SS_LIGHT_NAME,         //Key for sensor name
                                                             DeviceInfoKey.K.SS_LIGHT_VENDOR,       //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_LIGHT_VERSION,      //Key for sensor version
                                                             DeviceInfoKey.K.SS_LIGHT_POWER,        //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_LIGHT_RESOLUTION,   //Key for sensor resolution
                                                             DeviceInfoKey.K.SS_LIGHT_MAX,          //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_LIGHT_MIN_DELAY);   //Key for sensor's minimum delay
    /**Key set for linear acceleration sensor.*/
    private static final KeySet     KEYSET_LINE = new KeySet(DeviceInfoKey.K.SS_LINEAR_NAME,        //Key for sensor name
                                                             DeviceInfoKey.K.SS_LINEAR_VENDOR,      //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_LINEAR_VERSION,     //Key for sensor version
                                                             DeviceInfoKey.K.SS_LINEAR_POWER,       //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_LINEAR_RESOLUTION,  //Key for sensor resolution
                                                             DeviceInfoKey.K.SS_LINEAR_MAX,         //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_LINEAR_MIN_DELAY);  //Key for sensor's minimum delay
    /**Key set for magnetic field sensor.*/
    private static final KeySet     KEYSET_MAG = new KeySet(DeviceInfoKey.K.SS_MAG_NAME,        //Key for sensor name
                                                            DeviceInfoKey.K.SS_MAG_VENDOR,      //Key for sensor vendor
                                                            DeviceInfoKey.K.SS_MAG_VERSION,     //Key for sensor version
                                                            DeviceInfoKey.K.SS_MAG_POWER,       //Key for sensor power consumption
                                                            DeviceInfoKey.K.SS_MAG_RESOLUTION,  //Key for sensor resolution
                                                            DeviceInfoKey.K.SS_MAG_MAX,         //Key for sensor's maximum range
                                                            DeviceInfoKey.K.SS_MAG_MIN_DELAY);  //Key for sensor's minimum delay
    /**Key set for orientation sensor.*/
    private static final KeySet     KEYSET_ORIE = new KeySet(DeviceInfoKey.K.SS_ORIENT_NAME,        //Key for sensor name
                                                             DeviceInfoKey.K.SS_ORIENT_VENDOR,      //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_ORIENT_VERSION,     //Key for sensor version
                                                             DeviceInfoKey.K.SS_ORIENT_POWER,       //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_ORIENT_RESOLUTION,  //Key for sensor resolution
                                                             DeviceInfoKey.K.SS_ORIENT_MAX,         //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_ORIENT_MIN_DELAY);  //Key for sensor's minimum delay
    /**Key set for pressure sensor.*/
    private static final KeySet     KEYSET_PRES = new KeySet(DeviceInfoKey.K.SS_PRESSURE_NAME,      //Key for sensor name
                                                             DeviceInfoKey.K.SS_PRESSURE_VENDOR,    //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_PRESSURE_VERSION,   //Key for sensor version
                                                             DeviceInfoKey.K.SS_PRESSURE_POWER,     //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_PRESSURE_RESOLUTION,//Key for sensor resolution
                                                             DeviceInfoKey.K.SS_PRESSURE_MAX,       //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_PRESSURE_MIN_DELAY);//Key for sensor's minimum delay
    /**Key set for proximity sensor.*/
    private static final KeySet     KEYSET_PROX = new KeySet(DeviceInfoKey.K.SS_PROXIMITY_NAME,     //Key for sensor name
                                                            DeviceInfoKey.K.SS_PROXIMITY_VENDOR,    //Key for sensor vendor
                                                            DeviceInfoKey.K.SS_PROXIMITY_VERSION,   //Key for sensor version
                                                            DeviceInfoKey.K.SS_PROXIMITY_POWER,     //Key for sensor power consumption
                                                            DeviceInfoKey.K.SS_PROXIMITY_RESOLUTION,//Key for sensor resolution
                                                            DeviceInfoKey.K.SS_PROXIMITY_MAX,       //Key for sensor's maximum range
                                                            DeviceInfoKey.K.SS_PROXIMITY_MIN_DELAY);//Key for sensor's minimum delay
    /**Key set for rotation vector sensor.*/
    private static final KeySet     KEYSET_ROT = new KeySet(DeviceInfoKey.K.SS_ROT_NAME,        //Key for sensor name
                                                            DeviceInfoKey.K.SS_ROT_VENDOR,      //Key for sensor vendor
                                                            DeviceInfoKey.K.SS_ROT_VERSION,     //Key for sensor version
                                                            DeviceInfoKey.K.SS_ROT_POWER,       //Key for sensor power consumption
                                                            DeviceInfoKey.K.SS_ROT_RESOLUTION,  //Key for sensor resolution
                                                            DeviceInfoKey.K.SS_ROT_MAX,         //Key for sensor's maximum range
                                                            DeviceInfoKey.K.SS_ROT_MIN_DELAY);  //Key for sensor's minimum delay
    /**Key set for ambient temperature sensor.*/
    private static final KeySet     KEYSET_TEMP = new KeySet(DeviceInfoKey.K.SS_TEMP_NAME,      //Key for sensor name
                                                             DeviceInfoKey.K.SS_TEMP_VENDOR,    //Key for sensor vendor
                                                             DeviceInfoKey.K.SS_TEMP_VERSION,   //Key for sensor version
                                                             DeviceInfoKey.K.SS_TEMP_POWER,     //Key for sensor power consumption
                                                             DeviceInfoKey.K.SS_TEMP_RESOLUTION,//Key for sensor resolution
                                                             DeviceInfoKey.K.SS_TEMP_MAX,       //Key for sensor's maximum range
                                                             DeviceInfoKey.K.SS_TEMP_MIN_DELAY);//Key for sensor's minimum delay
    /**List of ket set for sensors.*/
    private static final KeySet[]   KEYSET = new KeySet[]
    {
        KEYSET_ACC,
        KEYSET_GRAV,
        KEYSET_GYRO,
        KEYSET_HUMI,
        KEYSET_LIGH,
        KEYSET_LINE,
        KEYSET_MAG,
        KEYSET_ORIE,
        KEYSET_PRES,
        KEYSET_PROX,
        KEYSET_ROT,
        KEYSET_TEMP
    };
    
    
    /**Build information of sensors.
     * @param di    [out] Repository of device information.*/
    static void
    Build(DeviceInfo di)
    {
        SensorManager oMgr = null;
        List<Sensor> oLst = null;
        
        //Clean sensors information by default value
        for(KeySet oKey: KEYSET) {
            di.Put(oKey.getKey4SensorName(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorVendor(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorVer(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorPwrConsumption(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorRes(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorMaxRange(), CONSTS.UNAVAILABLE);
            di.Put(oKey.getKey4SensorMinDelay(), CONSTS.UNAVAILABLE);
        }   
        
        //Dump sensor list
        if(((oMgr = MiscUtil.GetSensorManager()) != null) &&
           ((oLst = oMgr.getSensorList(Sensor.TYPE_ALL)) != null) &&
           !oLst.isEmpty()) {
                        
           ArrayList<Integer> oTypes = new ArrayList<Integer> (oLst.size());
           Iterator<Sensor> oIter = oLst.iterator();
           HashMap<String, ArrayList<String>> oVal = new HashMap<String, ArrayList<String>> ();
           Iterator<String> oIterKey = null;
           
           //Handle sensors' information one by one
           while(oIter.hasNext()) {
               Sensor oItm = oIter.next();
               KeySet oKey = null;
               
               if(aDebug.ENABLED) {
                   aDebug.d(LOG_TAG, "sensor type=" + oItm.getType());
                   aDebug.d(LOG_TAG, "  name=" + oItm.getName());
                   aDebug.d(LOG_TAG, "  vendor=" + oItm.getVendor());
                   aDebug.d(LOG_TAG, "  power=" + oItm.getPower());
                   aDebug.d(LOG_TAG, "  resolution=" + oItm.getResolution());
                   aDebug.d(LOG_TAG, "  max range=" + oItm.getMaximumRange());
               }
               
               //Put sensor information into device information
               if((oKey = getKeySet(oItm.getType())) != null) {
                   ArrayList<String> oName = null;
                   ArrayList<String> oVend = null;
                   ArrayList<String> oVer = null;
                   ArrayList<String> oPwr = null;
                   ArrayList<String> oRes = null;
                   ArrayList<String> oMax = null;
                   ArrayList<String> oDelay = null;
                   int iDelay = -1;
                   
                   //Prepare list of value
                   if((oName = oVal.get(oKey.getKey4SensorName())) == null) {
                       oName = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorName(), oName);
                   }
                   if((oVend = oVal.get(oKey.getKey4SensorVendor())) == null) {
                       oVend = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorVendor(), oVend);
                   }
                   if((oVer = oVal.get(oKey.getKey4SensorVer())) == null) {
                       oVer = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorVer(), oVer);
                   }
                   if((oPwr = oVal.get(oKey.getKey4SensorPwrConsumption())) == null) {
                       oPwr = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorPwrConsumption(), oPwr);
                   }
                   if((oRes = oVal.get(oKey.getKey4SensorRes())) == null) {
                       oRes = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorRes(), oRes);
                   }
                   if((oMax = oVal.get(oKey.getKey4SensorMaxRange())) == null) {
                       oMax = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorMaxRange(), oMax);
                   }
                   if((oDelay = oVal.get(oKey.getKey4SensorMinDelay())) == null) {
                       oDelay = new ArrayList<String> (2);
                       oVal.put(oKey.getKey4SensorMinDelay(), oDelay);
                   }
                   
                   //Set value of sensor into list
                   oName.add(oItm.getName());
                   oVend.add(oItm.getVendor());
                   oVer.add(String.valueOf(oItm.getVersion()));
                   oPwr.add(String.valueOf(oItm.getPower()));
                   oRes.add(String.valueOf(oItm.getResolution()));
                   oMax.add(String.valueOf(oItm.getMaximumRange()));
                   oDelay.add(((iDelay = Wrapper.GetSensorMinDelay(oItm)) >= 0)? String.valueOf(iDelay): CONSTS.UNAVAILABLE);
               }
               
               //Put sensor type into sensor type list
               if(!oTypes.contains(oItm.getType()))
                   oTypes.add(oItm.getType());
           }
           
           //Dump list of value into device information
           oIterKey = oVal.keySet().iterator(); 
           while(oIterKey.hasNext()) {
               String szKey = oIterKey.next();
               ArrayList<String> listVal = oVal.get(szKey);
               if((listVal != null) && !listVal.isEmpty())
                   di.Put(szKey, listVal);
           }   
           
           //Put available sensor type into device information
           if(!oTypes.isEmpty())
             di.Put(DeviceInfoKey.K.SS_AVAILABLE_TYPE, oTypes);  
        }
    }
    
    /**Get key set by sensor type.
     * @param iType [in] Type of sensor.<p>
     *              This parameter should be one of TYPE_xxx definition at android.hardware.Sensor.
     * @return      Return key set for sensor type, return null if not found.*/
    public static KeySet getKeySet(int iType)
    {
        KeySet  returnObj = null;
        switch(iType)
        {
            case 1:     //Sensor.TYPE_ACCELEROMETER at API level 3
                returnObj = KEYSET_ACC;               
                break;
            case 9:     //Sensor.TYPE_GRAVITY at API level 9
                returnObj = KEYSET_GRAV;
                break;
            case 4:     //Sensor.TYPE_GYROSCOPE at API level 3
                returnObj = KEYSET_GYRO;
                break;
            case 5:     //Sensor.TYPE_LIGHT at API level 3
                returnObj = KEYSET_LIGH;
                break;
            case 10:    //Sensor.TYPE_LINEAR_ACCELERATION at API level 9
                returnObj = KEYSET_LINE;
                break;
            case 2:     //Sensor.TYPE_MAGNETIC_FIELD at API level 3
                returnObj = KEYSET_MAG;
                break;
            case 3:     //Sensor.TYPE_ORIENTATION at API level 3
                returnObj = KEYSET_ORIE;
                break;
            case 6:     //Sensor.TYPE_PRESSURE at API level 3
                returnObj = KEYSET_PRES;
                break;
            case 8:     //Sensor.TYPE_PROXIMITY at API level 3
                returnObj = KEYSET_PROX;
                break;
            case 12:    //Sensor.TYPE_RELATIVE_HUMIDITY at API level 14
                returnObj = KEYSET_HUMI;
                break;
            case 11:    //Sensor.TYPE_ROTATION_VECTOR at API level 9
                returnObj = KEYSET_ROT;
                break;
            case 7:     //Sensor.TYPE_TEMPERATURE at API level 3
            case 13:    //Sensor.TYPE_AMBIENT_TEMPERATURE at API level 14
                returnObj = KEYSET_TEMP;
                break;
            default:
                //asus/Transformer TF101 will get "0"
                if(aDebug.ENABLED)
                    aDebug.d(LOG_TAG, String.format("Unknow sensor type: %d", iType));
                break;        
        }
        return returnObj;
    }
    
    
    
    /**Key set in INK.json*/
    public static class KeySet {        
        /**Key for sensor name.*/
        private String  m_szName = null;
        /**Key for sensor's vendor.*/
        private String  m_szVendor = null;
        /**Key for sensor's version.*/
        private String  m_szVer = null;
        /**Key for sensor's power consumption in mA.*/
        private String  m_szPwr = null;
        /**Key for sensor's resolution.*/
        private String  m_szResolution = null;
        /**Key for sensor's maximum range.*/
        private String  m_szMaxVal = null;
        /**Key for sensor's minimum delay between events in milliseconds.*/
        private String  m_szDelay = null;
        
        /**Constructor.
         * @param szName        [in] Key for sensor name.
         * @param szVendor      [in] Key for sensor's vendor.
         * @param szVer         [in] Key for sensor's version.
         * @param szPwr         [in] Key for sensor's power consumption in mA.
         * @param szResolution  [in] Key for sensor's resolution.
         * @param szMaxVal      [in] Key for sensor's maximum range.
         * @param szDelay       [in] Key for sensor's minimum delay between events in milliseconds.*/
        protected 
        KeySet(String szName,  String szVendor,    String szVer,
               String szPwr,   String szResolution,String szMaxVal,
               String szDelay) 
        {
            m_szName = szName;
            m_szVendor = szVendor;
            m_szVer = szVer;
            m_szPwr = szPwr;
            m_szResolution = szResolution;
            m_szMaxVal = szMaxVal;
            m_szDelay = szDelay;
        }
        
        /**Get key for sensor name.
         * @return  Return key of sensor name.*/
        public String 
        getKey4SensorName()
        {
            return m_szName;
        }
        
        /**Get key for sensor's vendor.
         * @return  Return key of sensor's vendor.*/
        public String 
        getKey4SensorVendor()
        {
            return m_szVendor;
        }
        
        /**Get key for sensor's version.
         * @return  Return key of sensor version.*/
        public String 
        getKey4SensorVer()
        {
            return m_szVer;
        }
        
        /**Get key for sensor's power consumption.
         * @return  Return key of sensor's power consumption.*/
        public String 
        getKey4SensorPwrConsumption()
        {
            return m_szPwr;
        }
        
        /**Get key for sensor's resolution.
         * @return  Return key of sensor's resolution.*/
        public String 
        getKey4SensorRes()
        {
            return m_szResolution;
        }
        
        /**Get key for sensor's maximum range.
         * @return  Return key of sensor's maximum range.*/
        public String 
        getKey4SensorMaxRange()
        {
            return m_szMaxVal;
        }
        
        /**Get key for sensor's minimum delay.
         * @return  Return key of sensor's minimum delay.*/
        public String 
        getKey4SensorMinDelay()
        {
            return m_szDelay;
        }
    };    
}
